package com.nononsenseapps.feeder.ui

import android.annotation.SuppressLint
import android.app.ActivityManager
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.view.*
import android.widget.Toast
import androidx.activity.FullyDrawnReporter
import androidx.activity.viewModels
import androidx.annotation.DrawableRes
import androidx.annotation.MenuRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.Toolbar
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import com.gitee.wsl.ext.base.isFalse
import com.gitee.wsl.task.DelayTwiceRun
import com.google.android.material.appbar.AppBarLayout
import com.leinardi.android.speeddial.AdvSpeedDialView
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.nononsenseapps.feeder.db.ARG
import com.nononsenseapps.feeder.db.entity.Feed
import com.nononsenseapps.feeder.db.room.*
import com.nononsenseapps.feeder.glide.GlideCacheUtil
import com.nononsenseapps.feeder.model.FeedListViewModel
import com.nononsenseapps.feeder.ui.base.CoroutineScopedActivity
import com.nononsenseapps.feeder.ui.base.startFeedNavigation
import com.nononsenseapps.feeder.ui.home.FeedsAdapter
import com.nononsenseapps.feeder.ui.home.OnNavigationItemClickListener
import com.nononsenseapps.feeder.ui.rule.FeedRuleListActivity
import com.nononsenseapps.feeder.util.*
import com.nononsenseapps.feeder.worker.configurePeriodicSync
import com.nononsenseapps.feeder.worker.isOkToSyncAutomatically
import com.nononsenseapps.feeder.worker.requestFeedSync
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.joda.time.DateTime
import timber.log.Timber
import java.net.URL
import java.util.*

abstract class AbstractFeedActivity:  CoroutineScopedActivity() {
    var gestureDetector: GestureDetector?=null

    var fullScreen:Boolean=false

    protected val twiceCheckDelay by lazy {
        DelayTwiceRun.build {
            onFirstPressed {
                Toast.makeText(this@AbstractFeedActivity, "再按一次退出", Toast.LENGTH_SHORT).show()
            }
            onFinish {
                this@AbstractFeedActivity.finish()
            }
        }
    }

    protected lateinit var navAdapter: FeedsAdapter

    protected val navController: NavController by lazy {
        findNavController(navHostFragment())
    }

    //protected val feedListViewModel: FeedListViewModel by lazy{ getFeedListViewModel() }

    protected val feedListViewModel: FeedListViewModel by viewModels()

    var fabClickListener:FabClickListener? = null

    init {

        // Enable periodic sync
        lifecycleScope.launchWhenCreated {

            handler.postDelayed({ configurePeriodicSync(applicationContext) },2000)

            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
                Timber.d("Lifecycle.State.STARTED start...")
                feedListViewModel.liveFeedsWithUnreadCounts.collect{ feeds->
                    withContext(Dispatchers.Main){
                        //Timber.d("liveFeedsWithUnreadCounts changed...")
                        navAdapter.submitList(feeds)
                    }
                }
            }
        }

        EventBusUtils.addCurrentlyFabShowStateChangeListener(this@AbstractFeedActivity){
            //Timber.d("EventBusUtils FabShowStateChangeListener change to visable:$it")
            if(getFab().isVisible != it)
               if (it) getFab().show() else getFab().hide()
        }
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
        super.onCreate(savedInstanceState)

        // Write default setting if method has never been called before
        PreferenceManager.setDefaultValues(this, R.xml.settings, false)

        // Not persisted so set nightmode every time we start
        AppCompatDelegate.setDefaultNightMode(settingsViewModel.themePreference)

        initFeedActivityView()

        lifecycleScope.launch(Dispatchers.IO) {
            //feedDao.mustExist(FEED_ALL(this@AbstractFeedActivity))
            feedDao.isExitsFeed(READ_LATE_FEED_ID).isFalse {
                feedDao.mustExist(
                    Feed(
                        READ_LATE_FEED_ID,
                        title = getString(R.string.feed_read_late),
                        customTitle = getString(R.string.feed_read_late),
                        url = URL("http://localhost/READ_LATE_FEED_ID")
                    )
                )
            }

            feedDao.isExitsFeed(MEMO_FEED_ID).isFalse {
                feedDao.mustExist(
                    Feed(
                    MEMO_FEED_ID,
                    title = getString(R.string.feed_memo),
                    customTitle = getString(R.string.feed_memo),
                    url = URL("http://localhost/MEMO_FEED_ID")
                )
                )

            feedDao.isExitsFeed(BACKUP_FEED_ID).isFalse {
                feedDao.mustExist(
                    Feed(
                    BACKUP_FEED_ID,
                    title = getString(R.string.feed_backup),
                    customTitle = getString(R.string.feed_backup),
                    url = URL("http://localhost/BACKUP_FEED_ID")
                )
                )
            }

            feedDao.isExitsFeed(HOT_FEED_ID).isFalse {
                feedDao.mustExist(
                    Feed(
                        FAVORITE_FEED_ID,
                        title = getString(R.string.title_activity_favorite),
                        customTitle = getString(R.string.title_activity_favorite),
                        url = URL("http://localhost/FAVORITE_FEED_ID")
                )
                )
                feedDao.mustExist(
                    Feed(
                        RULE_FEED_ID,
                        title = getString(R.string.title_system_feed_rule),
                        customTitle = getString(R.string.title_system_feed_rule),
                        url = URL("http://localhost/RULE_FEED_ID")
                )
                )
                feedDao.mustExist(
                    Feed(
                        HOT_FEED_ID,
                        title = getString(R.string.title_system_feed_hot),
                        customTitle = getString(R.string.title_system_feed_hot),
                        url = URL("http://localhost/HOT_FEED_ID")
                )
                )
                feedDao.mustExist(
                    Feed(
                        RECYCLE_FEED_ID,
                        title = getString(R.string.title_system_feed_recycle),
                        customTitle = getString(R.string.title_system_feed_recycle),
                        url = URL("http://localhost/RECYCLE_FEED_ID")
                )
                )
                feedDao.mustExist(
                    Feed(
                        STORE_FEED_ID,
                        title = getString(R.string.title_system_feed_store),
                        customTitle = getString(R.string.title_system_feed_store),
                        url = URL("http://localhost/STORE_FEED_ID")
                )
                )
            }
            }
        }

        settingsViewModel.liveThemePreference.observe(this, androidx.lifecycle.Observer {
            delegate.localNightMode = it
        })


        // When the user runs the app for the first time, we want to land them with the
        // navigation drawer open. But just the first time.
        if (!PrefUtils.isWelcomeDone(this)) {
            AlertDialog.Builder(this)
                .setTitle(getString(R.string.dialog_feed_demo_title))
                .setMessage(getString(R.string.dialog_feed_demo))
                .setPositiveButton(getString(R.string.action_cancel), DialogInterface.OnClickListener { dialog, _ ->
                    dialog.dismiss()
                })
                .setNegativeButton(getString(R.string.action_enter),  DialogInterface.OnClickListener { dialog, _ ->
                    startFeedNavigation(this,"https://raw.githubusercontent.com/wushunlian/app/master/feeder/opml/sample.opml")
                    dialog.dismiss()
                }).show()

            // first run of the app starts with the nav drawer open
            PrefUtils.markWelcomeDone(this)
        }

        handleSettingIntent()
    }

    abstract fun initFeedActivityView()

    fun hideableToolbar() {
        getToolBar().layoutParams = getToolBar().layoutParams.also {
            if (it is AppBarLayout.LayoutParams) {
                it.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP or AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
            }
        }
    }

    fun fixedToolbar() {
        getToolBar().layoutParams = getToolBar().layoutParams.also {
            if (it is AppBarLayout.LayoutParams) {
                it.scrollFlags = 0
            }
        }
    }

    fun initFab(@DrawableRes id: Int, fabClickListener: FabClickListener){
        getFab().setImageResource(id)
        getFab().clearActionItems()
        this.fabClickListener=fabClickListener
    }
    
    fun initFab(@DrawableRes id: Int, @MenuRes contextMenuId : Int,hotCount :Int = 1, fabClickListener: FabClickListener){
        getFab().setImageResource(id)
        getFab().hotCount = hotCount
        getFab().inflate(contextMenuId)
        this.fabClickListener=fabClickListener
    }

    abstract fun navHostFragment():Int

    abstract fun getFab(): AdvSpeedDialView

    abstract fun getToolBar():Toolbar

    abstract fun handleSettingIntent()

    abstract fun navigateToFeedRuleFragment(feedId: Long?=0, regContent: String?=null, adFlag: Boolean?=null)

    fun showFeedRuleActivity(feedId: Long){
        val intent=Intent(this, FeedRuleListActivity::class.java)
        intent.putExtra(ARG.FEED_ID,feedId)
        startActivity(intent)
    }

    @SuppressLint("MissingSuperCall")
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        intent?.let { setIntent(intent) }
        handleSettingIntent()
    }

    override fun onStart() {
        super.onStart()
        this.reportFullyDrawn()
    }


    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        return true
    }


    override fun onTouchEvent(event: MotionEvent?): Boolean {

        event?.let {event-> gestureDetector?.let{
            return it.onTouchEvent(event)
        } }

        return super.onTouchEvent(event)
    }

    protected fun syncFeedsMaybe() {
        if (!PrefUtils.shouldSyncOnResume(applicationContext)) {
            return
        }

        if (isOkToSyncAutomatically(applicationContext)) {
            requestFeedSync(context = applicationContext,
                    ignoreConnectivitySettings = false,
                    forceNetwork = false,
                    parallell = true)
        }
    }


    abstract fun openNavDrawer()

    fun changeFullScreen(){
        if(fullScreen){
            window.setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
        }else{
            window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
        }
        fullScreen=!fullScreen
    }


    protected fun doSomethingMemoryIntensive() {

        // Before doing something that requires a lot of memory,
        // check to see whether the device is in a low memory state.
        val memoryInfo = getAvailableMemory()

        if (memoryInfo.lowMemory) {
            Timber.d("low memory.total:%s\t\tavail:%s", MediaFileUtil.getFormatSize(memoryInfo.totalMem.toDouble()), MediaFileUtil.getFormatSize(memoryInfo.availMem.toDouble()))
            // Do memory intensive work ...
            GlideCacheUtil.getInstance().clearImageMemoryCache(this)
        }
    }

    // Get a MemoryInfo object for the device's current memory status.
    private fun getAvailableMemory(): ActivityManager.MemoryInfo {
        val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val memoryInfo = ActivityManager.MemoryInfo()
        activityManager.getMemoryInfo(memoryInfo)
        return memoryInfo
    }

    abstract inner class AbstractOnNavigationItemClickListener : OnNavigationItemClickListener{

        override fun deleteFeed(id: Long) {
            lifecycleScope.launch(Dispatchers.IO) {
                feedDao.deleteFeed(Feed(id))
            }
        }

        override fun deleteFeedsInTag(tag: String) {
            lifecycleScope.launch(Dispatchers.IO) {
                feedDao.deleteFeedsInTag(tag)
            }
        }

        override fun markAddFeedRule(id: Long) {
            navigateToFeedRuleFragment(id)
        }

        override fun makeFeedAsRead(id: Long,dateBefore: Date?) {
            lifecycleScope.launch(Dispatchers.IO) {
                if(dateBefore==null)
                    if(id == ID_ALL_FEEDS)
                        feedItemDao.markAllAsRead()
                    else
                      feedItemDao.markAllAsRead(id)
                else
                    if(id == ID_ALL_FEEDS)
                        feedItemDao.markAllAsRead(DateTime(dateBefore.time))
                    else
                        feedItemDao.markAllAsRead(id, DateTime(dateBefore.time))
            }
        }

        override fun readAllWithFeedTag(tag: String,dateBefore: Date?) {
            lifecycleScope.launch(Dispatchers.IO) {
                if(dateBefore==null)
                    feedItemDao.markAllAsRead(tag)
                else
                    feedItemDao.markAllAsRead(tag,DateTime(dateBefore.time))
            }
        }

        override fun syncFeedWithId(id: Long) {
            lifecycleScope.launch(Dispatchers.IO) {
                requestFeedSync(
                        context = this@AbstractFeedActivity,
                        feedId = id,
                        ignoreConnectivitySettings = true,
                        force = true,
                        parallell = true,
                        forceNetwork = true
                )
            }
        }

        override fun syncFeedWithTag(tag: String) {
            lifecycleScope.launch(Dispatchers.IO) {
                requestFeedSync(
                        context = this@AbstractFeedActivity,
                        feedTag = tag,
                        ignoreConnectivitySettings = true,
                        force = true,
                        parallell = true,
                        forceNetwork = true
                )
            }
        }

        override fun clearFeedItem(feedId: Long) {
            lifecycleScope.launch(Dispatchers.IO) {
                if(feedId!= RECYCLE_FEED_ID)
                    feedItemDao.moveFeedToFeed(feedId, RECYCLE_FEED_ID)
                else
                   feedItemDao.deleteAllInFeed(feedId)
            }
        }

        override fun moveFeedToFeed(frommFeedId: Long, toFeedId: Long) {
            lifecycleScope.launch(Dispatchers.IO) {
                feedItemDao.moveFeedToFeed(frommFeedId,toFeedId)
            }
        }


        override fun toggleFeedReadable(feedId: Long, readable: Boolean) {
            lifecycleScope.launch(Dispatchers.IO) {
                if(ID_ALL_FEEDS==feedId)
                   feedDao.toggleAllFeedReadable(readable)
                else
                   feedDao.toggleFeedReadable(feedId,readable)
            }
        }

        override fun toggleFeedWithTagReadable(tag: String, readable: Boolean) {
            lifecycleScope.launch(Dispatchers.IO) {
                feedDao.toggleFeedWithTagReadable(tag,readable)
            }
        }

        override fun markFeedRuleAble(id: Long, ruleAble: Boolean) {
            lifecycleScope.launch(Dispatchers.IO) {
                feedDao.markFeedRuleAble(id,ruleAble)
            }
        }

        override fun markFeedAttentionLevel(feedId: Long, attentionLevel: Int) {
            lifecycleScope.launch(Dispatchers.IO) {
                feedDao.changeFeedAttentionLevel(feedId,attentionLevel)
            }
        }
    }
}

interface FabClickListener{
    fun fabOnClickListener() 
    fun fabOnDoubleClickListener(){}
    fun fabOnLongClickListener() {}
    fun onActionSelected(actionItem: SpeedDialActionItem?): Boolean{return false}
}